#include "tasks.h"
#include <stdlib.h>
#include <iostream>
using namespace std;

void TaskCPU(int pid, vector<int> params) { // params: n
	uso_CPU(pid, params[0]); // Uso el CPU n milisegundos.
}

void TaskIO(int pid, vector<int> params) { // params: ms_pid, ms_io,
	uso_CPU(pid, params[0]); // Uso el CPU ms_pid milisegundos.
	uso_IO(pid, params[1]); // Uso IO ms_io milisegundos.
}

void TaskAlterno(int pid, vector<int> params) { // params: ms_pid, ms_io, ms_pid, ...
	for(int i = 0; i < (int)params.size(); i++) {
		if (i % 2 == 0) uso_CPU(pid, params[i]);
		else uso_IO(pid, params[i]);
	}
}

void TaskConsola(int pid, vector<int> params) { // params: n, bmin y bmax.
	
	for(int i = 0; i < params[0]; i++) {
		int duracion = (rand() % (params[2] - params[1])) + params[1];
		uso_IO(pid, duracion);
	}
}

int rand(int min, int max){
	//Devuelve un numero random entre min y maximo (incluye minimo y maximo).
	int nrand = (rand() % (max - min + 1)) + min;
	return nrand;
}

void TaskBatch(int pid, vector<int> params) { // params: cant cpu, n bloqueante.
	
	int ini = 0;
	int fin = params[0] + params[1]-1;
	int tiempo_uso_cpu;
	int tiempo_restante_uso_cpu = params[0];
	int tiempo_llamada_bloqueante = 1;
	int iteracion = 0;

	//~ cout << "TaskBatch - Datos iniciales:\nTaskBatch - ini: " << ini << "\nTaskBatch - fin: " << fin << endl;
	//~ cout << "TaskBatch - Cantidad llamadas bloqueantes: " << params[1] << "\nTaskBatch - tiempoCPURestante: " << tiempo_restante_uso_cpu << endl;

	if(params[0]!=params[1]){
		for(int i = params[1]; i > 0; i--) {
			//~ cout<< "TaskBatch - Iteracion " << iteracion << ": " << endl;
			tiempo_uso_cpu = rand(ini, fin-i*2);	
			//~ cout << "TaskBatch - Obteniendo un numero random entre " << ini << " y " << fin -i*2<< ". \nTaskBatch - Numero obtenido: " << tiempo_uso_cpu << endl;
			if(tiempo_uso_cpu != 0){
				
				tiempo_uso_cpu = tiempo_uso_cpu - ini;	
				//~ if(ini>1){tiempo_uso_cpu--;}		
				if(tiempo_uso_cpu <= 0){
					tiempo_uso_cpu = 0;
				}
				//~ cout << "TaskBatch - Utilizando cpu - duracion: " << tiempo_uso_cpu << endl;
				uso_CPU(pid, tiempo_uso_cpu);
				tiempo_restante_uso_cpu = tiempo_restante_uso_cpu - tiempo_uso_cpu;
			}
			//~ cout << "TaskBatch - Llamada bloqueante - duracion: 2 (1 ciclo uso cpu + 1 ciclo bloqueada)" << endl;
			uso_IO(pid, tiempo_llamada_bloqueante); //Consume un ciclo usando la CPU y luego bloquea durante 1 ciclo. 
					//En este task no hay que tener en cuenta el tiempo 
					//que permanece bloqueada pero si el primer ciclo que usa la cpu.		
			tiempo_restante_uso_cpu--;
			//tiempo cpu+clock io+clock bloqueando+1 del sigte posic
			ini = ini+tiempo_uso_cpu + tiempo_llamada_bloqueante + 1; //tiempu_uso_cpu + 2  NOTA: lote2.tsk + primer random 8 falla. 
			iteracion++;
			//~ fin = fin - iteracion;

			//~ cout << "TaskBatch - ini: " << ini << "\nTaskBatch - fin: " << fin << "\nTaskBatch - tiempo_uso_cpu: " << tiempo_uso_cpu << "\nTaskBatch - tiempoCPURestante: " << tiempo_restante_uso_cpu << endl;
		}
		//~ cout << "TaskBatch - Consumiendo tiempo restante: " << tiempo_restante_uso_cpu << endl;
		if(tiempo_restante_uso_cpu>0){
			uso_CPU(pid, tiempo_restante_uso_cpu);
		}
	}else{
		//~ cout<< "TaskBatch - #llamadas_bloqueantes = #uso_cpu " << endl;
		for(int i=params[1];i>0;i--){
			//~ cout << "uso_io " << i << endl;
			uso_IO(pid, tiempo_llamada_bloqueante);
		}
	}
}

void tasks_init(void) {
	/* Todos los tipos de tareas se deben registrar acá para poder ser usadas.
	 * El segundo parámetro indica la cantidad de parámetros que recibe la tarea
	 * como un vector de enteros, o -1 para una cantidad de parámetros variable. */
	register_task(TaskCPU, 1);
	register_task(TaskIO, 2);
	register_task(TaskAlterno, -1);
	register_task(TaskConsola, 3);
	register_task(TaskBatch, 2);
}

